package ch.ethz.fcl.metrobuzz.viewer;

import java.awt.Canvas;
import java.awt.Rectangle;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

import javax.swing.JFrame;

import net.miginfocom.swing.MigLayout;

import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.PixelFormat;

import ch.ethz.fcl.metrobuzz.MBContainer;
import ch.ethz.fcl.metrobuzz.render.techniques.projection.Projection;

public class MBViewer {
	private ProjectionType projType;
	private Camera camera;
	private MBContainer container;
	private Projection proj;

	public static boolean newUpdate = false;

	// 3 (7 now with 4 projectors) touch-walls in value lab asia, others 1
	public static int numScreens = 7;

	public static int maximizedX = -8;
	public static int maximizedY = -8;
	public static int titleHeight = 48;

	private static JFrame frame;
	private Canvas canvas;

	private int frameWidth, frameHeight;
	private int canvasWidth, canvasHeight;

	public static boolean VIEW_PORT_CHANGED = false;

	public MBViewer(ProjectionType proj) {
		this.projType = proj;

		newUpdate = true;
		camera = new Camera(this.projType);
	}

	public MBViewer(ProjectionType proj, MBContainer container) {
		this.projType = proj;
		this.container = container;
		container.setView(this);

		newUpdate = true;
		camera = new Camera(this.projType);
	}

	public void createDisplay(int frameWidth, int frameHeight, int canvasWidth,
			int canvasHeight, String title) {
		createDisplay(0, 0, frameWidth, frameHeight, canvasWidth, canvasHeight,
				title);
	}

	/**
	 * put display in a canvas to enable resizable and make it consistent in
	 * different system (Mac don't have maximize button if simply
	 * Display.setResizable(true), whereas Windows has)
	 * 
	 * @param posX
	 * @param posY
	 * @param frameWidth
	 * @param frameHeight
	 * @param canvasWidth
	 * @param canvasHeight
	 * @param title
	 */
	public void createDisplay(int posX, int posY, int frameWidth,
			int frameHeight, int canvasWidth, int canvasHeight, String title) {
		this.frameWidth = frameWidth;
		this.frameHeight = frameHeight;
		this.canvasWidth = canvasWidth;
		this.canvasHeight = canvasHeight;

		frame = new JFrame(title);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setLayout(new MigLayout("ins 0", "", ""));

		frame.addKeyListener(new KeyAdapter() {
			@Override
			public void keyPressed(KeyEvent e) {
				if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
					System.exit(0);
				}
			}
		});

		frame.setLocation(posX, posY);

		frame.setUndecorated(false);

		canvas = new Canvas();
		canvas.setSize(canvasWidth, canvasHeight);
		canvas.setVisible(true);

		frame.add(canvas);
	}

	public void initFrame() {
		frame.setVisible(true);
		frame.pack();

		createDisplay();
	}

	private void createDisplay() {
		try {
			Display.setParent(canvas);
			Display.setDisplayMode(new DisplayMode(canvasWidth, canvasHeight));
			String sysName = System.getProperty("os.name");

			if (sysName.startsWith("Mac"))
				Display.create(new PixelFormat(0, 8, 4, 4));
			else if (sysName.startsWith("Windows"))
				Display.create(new PixelFormat(0, 8, 4, 4));
		} catch (Exception e) {
			System.err.println("Failed to create OpenGL due to " + e);
			System.exit(0);
		}
		camera.setup(frameWidth, frameHeight);

		proj = new Projection();
	}

	public void update() {
		camera.update();
	}

	public Camera getCamera() {
		return camera;
	}

	public MBContainer getContainer() {
		return container;
	}

	public Projection getProjection() {
		return proj;
	}

	public enum ProjectionType {
		Perspective, Ortho
	}

	public void reset() {
		camera.setTrackX(0);
		camera.setTrackY(0);
		camera.setPanX(0);
		camera.setPanY(0);
		camera.setPanZ(0);
		camera.setDistance(camera.getInitDistance());
		newUpdate = true;
	}

	public void recreate(boolean fullscreen) {
		Display.destroy();
		createDisplay();
	}

	public static int getWindowX() {
		if (frame != null)
			return frame.getX();
		else
			return Display.getX();
	}

	public static int getWindowY() {
		if (frame != null)
			return frame.getY();
		else
			return Display.getY();
	}

	public static int getWidth() {
		if (frame != null)
			return frame.getWidth();
		else
			return Display.getWidth();
	}

	public static int getHeight() {
		if (frame != null)
			return frame.getHeight();
		else
			return Display.getHeight();
	}

	public static Rectangle getBounds() {
		if (frame != null) {
			return frame.getBounds();
		} else
			return null;
	}

	public JFrame getFrame() {
		return frame;
	}
}
